package top.byteio.common.core.utils;

import lombok.experimental.UtilityClass;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
*  字符串工具类
* @author lerryxiaxia
*/
@UtilityClass
public class StringUtils {

    /**
     * 空字符串
     */
    private static final String EMPTY = "";

    /**
     * 判断字符串是否为空
     *
     * @param str 字符串
     * @return 是否为空
     */
    public static boolean isEmpty(final CharSequence str) {
        return str == null || str.isEmpty();
    }

    /**
     * 判断字符串是否不为空
     *
     * @param str 字符串
     * @return 是否不为空
     */
    public static boolean isNotEmpty(final CharSequence str) {
        return !isEmpty(str);
    }

    /**
     * 判断字符串是否为空白
     *
     * @param str 字符串
     * @return 是否为空白
     */
    public static boolean isBlank(final CharSequence str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断字符串是否不为空白
     *
     * @param str 字符串
     * @return 是否不为空白
     */
    public static boolean isNotBlank(final CharSequence str) {
        return !isBlank(str);
    }

    /**
     * 去除字符串两端空格
     *
     * @param str 字符串
     * @return 处理后的字符串
     */
    public static String trim(final String str) {
        return str == null ? null : str.trim();
    }

    /**
     * 去除字符串两端空格，如果为空则返回空字符串
     *
     * @param str 字符串
     * @return 处理后的字符串
     */
    public static String trimToEmpty(final String str) {
        return str == null ? EMPTY : str.trim();
    }

    /**
     * 去除字符串两端空格，如果为空则返回null
     *
     * @param str 字符串
     * @return 处理后的字符串
     */
    public static String trimToNull(final String str) {
        final String ts = trim(str);
        return isEmpty(ts) ? null : ts;
    }

    /**
     * 将字符串首字母大写
     *
     * @param str 字符串
     * @return 首字母大写的字符串
     */
    public static String capitalize(final String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return str;
        }

        final char firstChar = str.charAt(0);
        if (Character.isTitleCase(firstChar)) {
            return str;
        }

        return Character.toTitleCase(firstChar) +
                str.substring(1);
    }

    /**
     * 将字符串首字母小写
     *
     * @param str 字符串
     * @return 首字母小写的字符串
     */
    public static String uncapitalize(final String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return str;
        }

        final char firstChar = str.charAt(0);
        if (Character.isLowerCase(firstChar)) {
            return str;
        }

        return Character.toLowerCase(firstChar) +
                str.substring(1);
    }

    /**
     * 判断两个字符串是否相等
     *
     * @param str1 字符串1
     * @param str2 字符串2
     * @return 是否相等
     */
    public static boolean equals(final CharSequence str1, final CharSequence str2) {
        if (str1 == null && str2 == null) {
            return true;
        }
        if (str1 == null || str2 == null) {
            return false;
        }
        return str1.equals(str2);
    }

    /**
     * 判断两个字符串是否相等（忽略大小写）
     *
     * @param str1 字符串1
     * @param str2 字符串2
     * @return 是否相等
     */
    public static boolean equalsIgnoreCase(final String str1, final String str2) {
        if (str1 == null && str2 == null) {
            return true;
        }
        if (str1 == null || str2 == null) {
            return false;
        }
        return str1.equalsIgnoreCase(str2);
    }

    /**
     * 字符串连接
     *
     * @param separator 分隔符
     * @param array 数组
     * @return 连接后的字符串
     */
    public static String join(final Object[] array, final String separator) {
        if (array == null) {
            return null;
        }
        return join(Arrays.asList(array), separator);
    }

    /**
     * 字符串连接
     *
     * @param separator 分隔符
     * @param collection 集合
     * @return 连接后的字符串
     */
    public static String join(final Collection<?> collection, final String separator) {
        if (collection == null) {
            return null;
        }
        if (collection.isEmpty()) {
            return EMPTY;
        }

        final StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (final Object item : collection) {
            if (first) {
                first = false;
            } else {
                sb.append(separator);
            }
            sb.append(item);
        }
        return sb.toString();
    }

    /**
     * 字符串替换
     *
     * @param text 字符串
     * @param searchString 要替换的字符串
     * @param replacement 替换后的字符串
     * @return 替换后的字符串
     */
    public static String replace(final String text, final String searchString, final String replacement) {
        return replace(text, searchString, replacement, -1);
    }

    /**
     * 字符串替换
     *
     * @param text 字符串
     * @param searchString 要替换的字符串
     * @param replacement 替换后的字符串
     * @param max 最大替换次数
     * @return 替换后的字符串
     */
    public static String replace(final String text, final String searchString, final String replacement, int max) {
        if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
            return text;
        }

        int start = 0;
        int end = text.indexOf(searchString, start);
        if (end == -1) {
            return text;
        }
        final int replLength = searchString.length();
        int increase = replacement.length() - replLength;
        increase = Math.max(increase, 0);
        increase *= max < 0 ? 16 : Math.min(max, 64);
        final StringBuilder sb = new StringBuilder(text.length() + increase);
        while (end != -1) {
            sb.append(text, start, end).append(replacement);
            start = end + replLength;
            if (--max == 0) {
                break;
            }
            end = text.indexOf(searchString, start);
        }
        sb.append(text.substring(start));
        return sb.toString();
    }

    /**
     * 检查字符串是否包含指定字符序列
     *
     * @param str 字符串
     * @param searchStr 要查找的字符串
     * @return 是否包含
     */
    public static boolean contains(final CharSequence str, final CharSequence searchStr) {
        if (str == null || searchStr == null) {
            return false;
        }
        return str.toString().contains(searchStr);
    }

    /**
     * 检查字符串是否以指定前缀开头
     *
     * @param str 字符串
     * @param prefix 前缀
     * @return 是否以指定前缀开头
     */
    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
        return startsWith(str, prefix, false);
    }

    /**
     * 检查字符串是否以指定前缀开头（忽略大小写）
     *
     * @param str 字符串
     * @param prefix 前缀
     * @return 是否以指定前缀开头
     */
    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
        return startsWith(str, prefix, true);
    }

    /**
     * 检查字符串是否以指定前缀开头
     *
     * @param str 字符串
     * @param prefix 前缀
     * @param ignoreCase 是否忽略大小写
     * @return 是否以指定前缀开头
     */
    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
        if (str == null || prefix == null) {
            return str == null && prefix == null;
        }
        if (prefix.length() > str.length()) {
            return false;
        }
        return regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
    }

    /**
     * 删除字符串前缀,如果没有匹配的前缀则返回原字符串
     * @param source 源字符串
	 * @param prefix 前缀
	 * @param ignoreCase 是否忽略大小写
     * @return java.lang.String 删除后的字符串
     * @author lerryxia
     **/
    public static String deletePrefix(String source, String prefix,boolean ignoreCase) {
        if (startsWith(source, prefix, ignoreCase)){
            return source.substring(prefix.length());
        }
        return source;
    }

    /**
     * 检查字符串是否以指定后缀结尾
     *
     * @param str 字符串
     * @param suffix 后缀
     * @return 是否以指定后缀结尾
     */
    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
        return endsWith(str, suffix, false);
    }

    /**
     * 检查字符串是否以指定后缀结尾（忽略大小写）
     *
     * @param str 字符串
     * @param suffix 后缀
     * @return 是否以指定后缀结尾
     */
    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
        return endsWith(str, suffix, true);
    }


    /**
     * 检查字符串是否以指定后缀结尾
     *
     * @param str 字符串
     * @param suffix 后缀
     * @param ignoreCase 是否忽略大小写
     * @return 是否以指定后缀结尾
     */
    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
        if (str == null || suffix == null) {
            return str == null && suffix == null;
        }
        if (suffix.length() > str.length()) {
            return false;
        }
        final int strOffset = str.length() - suffix.length();
        return regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
    }

    /**
     * 区域匹配
     *
     * @param cs 字符序列
     * @param ignoreCase 是否忽略大小写
     * @param csStart 字符序列开始位置
     * @param substring 子字符串
     * @param start 子字符串开始位置
     * @param length 长度
     * @return 是否匹配
     */
    private static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int csStart,
                                         final CharSequence substring, final int start, final int length) {
        if (cs instanceof String && substring instanceof String) {
            return ((String) cs).regionMatches(ignoreCase, csStart, (String) substring, start, length);
        }
        int index1 = csStart;
        int index2 = start;
        int tmpLen = length;

        // 处理空字符串
        while (tmpLen-- > 0) {
            final char c1 = cs.charAt(index1++);
            final char c2 = substring.charAt(index2++);

            if (c1 == c2) {
                continue;
            }

            if (!ignoreCase) {
                return false;
            }

            // 大小写转换后比较
            if (Character.toUpperCase(c1) != Character.toUpperCase(c2) &&
                Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
                return false;
            }
        }

        return true;
    }

    /**
     * 检查字符串是否以指定的任意一个后缀结尾
     *
     * @param sourceName 要检查的源字符串
     * @param s1 可变参数，包含一个或多个后缀字符串
     * @return 如果源字符串以任意一个后缀结尾则返回true，否则返回false
     * @author lerryxia
     */
    public static boolean endsWithAny(String sourceName, String ...s1) {
        // 处理边界情况
        if (sourceName == null) {
            return false;
        }

        if (s1 == null) {
            return false;
        }

        // 检查sourceName是否以任意一个后缀结尾
        for (String suffix : s1) {
            if (suffix != null && sourceName.endsWith(suffix)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 将字符串按照指定分隔符分割成字符串列表
     *
     * @param source 待分割的源字符串，如果为null则返回空列表
     * @param delimiter 分割符，不能为null
     * @return 分割后的字符串列表
     * @throws IllegalArgumentException 当分隔符为null时抛出此异常
     */
    public static List<String> splitList(String source, String delimiter) {
        // 参数校验
        if (source == null) {
            return new ArrayList<>();
        }
        if (delimiter == null) {
            throw new IllegalArgumentException("Delimiter cannot be null");
        }

        // 执行分割操作
        String[] parts = source.split(delimiter);
        return Arrays.asList(parts);
    }


    /**
     * 格式化字符串模板，将模板中的占位符替换为对应的参数值
     * @param template 字符串模板，包含{}为占位符
     * @param params 用于替换占位符的参数数组
     * @return java.lang.String 将{}占位符替换为参数后的字符串，如果模板为null则返回null，如果参数为空则返回原模板
     * @author lerryxia
     **/
    public static String format(String template, Object... params) {
        if (template == null) {
            return null;
        }

        // 如果params为null，表示要去除占位符
        if (params == null) {
            return template.replaceAll("\\{\\}", "");
        }

        if (params.length == 0) {
            return template;
        }

        StringBuilder result = new StringBuilder();
        int startIndex = 0;
        int placeholderIndex = 0;

        while (startIndex < template.length()) {
            int openBraceIndex = template.indexOf('{', startIndex);
            if (openBraceIndex == -1 || openBraceIndex == template.length() - 1) {
                result.append(template.substring(startIndex));
                break;
            }

            if (template.charAt(openBraceIndex + 1) == '}') {
                result.append(template, startIndex, openBraceIndex);
                if (placeholderIndex < params.length) {
                    result.append(params[placeholderIndex]);
                } else {
                    result.append("{}");
                }
                placeholderIndex++;
                startIndex = openBraceIndex + 2;
            } else {
                result.append(template.charAt(startIndex));
                startIndex++;
            }
        }

        return result.toString();
    }
}
